package com.example.reverse;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

import java.io.File;
import java.util.*;

/**
 * <p>
 * 根据数据库表，逆向自动生成
 * Mapper接口,
 * xml文件,
 * service接口,
 * service实现
 * controller
 * Entity
 * Vo
 * Dto
 * </p>
 */
public class ReverseCode {

    public static void main(String[] args) {
        //读取配置文件
        final ResourceBundle rb = ResourceBundle.getBundle("mybatis-generator");

        // 代码生成器
        AutoGenerator mpg = new AutoGenerator();

        // 选择 freemarker 引擎，默认 Veloctiy
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());

        GlobalConfig gc = new GlobalConfig();
        String  defaultDirT = rb.getString("output.dir"),apiDirT = rb.getString("output.dir.api"),daoDirT = rb.getString("output.dir.dao");
        if (null == defaultDirT || Objects.equals("", defaultDirT.trim())){
            defaultDirT = gc.getOutputDir();
        }
        if (null == apiDirT || Objects.equals("", apiDirT.trim())){
            apiDirT = defaultDirT;
        }
        if (null == daoDirT || Objects.equals("", daoDirT.trim())){
            daoDirT = defaultDirT;
        }
        String defaultDirR = defaultDirT, apiDirR = apiDirT, daoDirR = daoDirT;
        // 全局配置
        gc.setOutputDir(defaultDirR);    //生成文件的输出目录
        gc.setAuthor(rb.getString("author"));           //作者
        gc.setFileOverride(true);                //是否覆盖已有文件 默认值：false
        gc.setOpen(false);                       //是否打开输出目录 默认值:true
        gc.setSwagger2(true);                    //开启 swagger2 模式 默认false
        gc.setBaseColumnList(true);              //开启 baseColumnList 默认false
        gc.setBaseResultMap(true);               //开启 BaseResultMap 默认false
        String entitySuffix = rb.getString("entity.suffix");
        boolean  tempBool = false;
        if(null != entitySuffix && !Objects.equals("",entitySuffix)){
            gc.setEntityName("%s" + entitySuffix);            //实体命名方式  默认值：null 例如：%sEntity 生成 UserEntity
            tempBool = !tempBool;
        }
        boolean bool  = tempBool;
        gc.setMapperName("%sMapper");            //mapper 命名方式 默认值：null 例如：%sDao 生成 UserDao
        gc.setXmlName("%sMapper");               //Mapper xml 命名方式   默认值：null 例如：%sDao 生成 UserDao.xml
        gc.setServiceName("%sService");          //service 命名方式   默认值：null 例如：%sBusiness 生成 UserBusiness
        gc.setServiceImplName("%sServiceImpl");  //service impl 命名方式  默认值：null 例如：%sBusinessImpl 生成 UserBusinessImpl
        gc.setControllerName("%sController");    //controller 命名方式    默认值：null 例如：%sAction 生成 UserAction
        mpg.setGlobalConfig(gc);

        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setDbType(DbType.MYSQL);        //数据库类型	该类内置了常用的数据库类型【必须】
        dsc.setUrl(rb.getString("jdbc.url"));
        dsc.setDriverName(rb.getString("jdbc.driver.class.name"));
        dsc.setUsername(rb.getString("jdbc.username"));
        dsc.setPassword(rb.getString("jdbc.password"));
        mpg.setDataSource(dsc);

        // 包配置
        PackageConfig pc = new PackageConfig();
        if (!Objects.equals("", rb.getString("module.name"))) {
            pc.setModuleName(rb.getString("module.name"));
        }
        pc.setParent(rb.getString("package.name"));
        mpg.setPackageInfo(pc);

        // 策略配置	数据库表配置，通过该配置，可指定需要生成哪些表或者排除哪些表
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);    //表名生成策略
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略, 未指定按照 naming 执行
        if (!Objects.equals("", rb.getString("include.tables.name"))) {//需要包含的表名，允许正则表达式（与exclude二选一配置）
            strategy.setInclude(rb.getString("include.tables.name").split(","));
        }
        if (!Objects.equals("", rb.getString("super.entity.class.name"))) {
            strategy.setSuperEntityClass(rb.getString("super.entity.class.name"));    //自定义继承的Entity类全称，带包名
        }
        if (!Objects.equals("", rb.getString("super.controller.class.name"))) {
            strategy.setSuperControllerClass(rb.getString("super.controller.class.name"));    //自定义继承的Controller类全称，带包名
        }
        strategy.setRestControllerStyle(Boolean.valueOf(rb.getString("rest.controller.style")));    //生成 @RestController 控制器
        strategy.setEntityLombokModel(Boolean.valueOf(rb.getString("entity.lombok.model")));//【实体】是否为lombok模型（默认 false）
        strategy.setControllerMappingHyphenStyle(true);    //驼峰转连字符
        strategy.setTablePrefix(pc.getModuleName() + "_");    //是否生成实体时，生成字段注解
        mpg.setStrategy(strategy);
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());


        Map<String, Object> map = new HashMap<>();

        // 自定义输出配置，会被优先输出
        List<FileOutConfig> focList = new ArrayList<>();
        // dto
        String dtoMark = rb.getString("dto.create.mark");
        if (null == dtoMark || Objects.equals("", dtoMark.trim()) || Boolean.valueOf(dtoMark)) {
            focList.add(new FileOutConfig(rb.getString("template.dto")) {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    StringBuffer expandSb = new StringBuffer(apiDirR);
                    expandSb.append("/").append(rb.getString("package.name").replaceAll("\\.", "/"));
                    if (!Objects.equals("", rb.getString("module.name"))) {
                        expandSb.append("/").append(rb.getString("module.name").replaceAll("\\.", "/"));
                    }
                    expandSb.append("/dto");
                    String dtoName = bool ? tableInfo.getEntityName().split(entitySuffix)[0] : tableInfo.getEntityName();
                    StringBuffer sb = new StringBuffer(dtoName).append("Dto");
                    map.put("dtoName",sb.toString());
                    String entityFile = String.format((expandSb + File.separator + "%s" + ".java"), sb.toString());
                    return entityFile;
                }
            });
        }
        //vo
        String voMark = rb.getString("vo.create.mark");
        if (null == voMark || Objects.equals("", voMark.trim()) || Boolean.valueOf(voMark)) {
            focList.add(new FileOutConfig(rb.getString("template.vo")) {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    StringBuffer expandSb = new StringBuffer(apiDirR);
                    expandSb.append("/").append(rb.getString("package.name").replaceAll("\\.", "/"));
                    if (!Objects.equals("", rb.getString("module.name"))) {
                        expandSb.append("/").append(rb.getString("module.name").replaceAll("\\.", "/"));
                    }
                    expandSb.append("/vo");
                    String dtoName = bool ? tableInfo.getEntityName().split(entitySuffix)[0] : tableInfo.getEntityName();
                    StringBuffer sb = new StringBuffer(dtoName).append("Vo");
                    map.put("voName",sb.toString());
                    String entityFile = String.format((expandSb + File.separator + "%s" + ".java"), sb.toString());
                    return entityFile;
                }
            });
        }

        //controller
        String controllerMark = rb.getString("controller.create.mark");
        if (null == controllerMark || Objects.equals("", controllerMark.trim()) || Boolean.valueOf(controllerMark)) {
            focList.add(new FileOutConfig(rb.getString("template.controller")) {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    StringBuffer expandSb = new StringBuffer(defaultDirR);
                    expandSb.append("/").append(rb.getString("package.name").replaceAll("\\.", "/"));
                    if (!Objects.equals("", rb.getString("module.name"))) {
                        expandSb.append("/").append(rb.getString("module.name").replaceAll("\\.", "/"));
                    }
                    expandSb.append("/controller");
                    String serviceName = bool ? tableInfo.getEntityName().split(entitySuffix)[0] : tableInfo.getEntityName();
                    StringBuffer sb = new StringBuffer(serviceName).append("Service");
                    map.put("serviceName",(new StringBuilder()).append(Character.toLowerCase(sb.charAt(0))).append(sb.substring(1)).toString());
                    String entityFile = String.format((expandSb + File.separator + "%s" + ".java"), tableInfo.getControllerName());
                    return entityFile;
                }
            });
        }

        //service
        String serviceMark = rb.getString("service.create.mark");
        if (null == serviceMark || Objects.equals("", serviceMark.trim()) || Boolean.valueOf(serviceMark)) {
            focList.add(new FileOutConfig(rb.getString("template.service")) {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    StringBuffer expandSb = new StringBuffer(defaultDirR);
                    expandSb.append("/").append(rb.getString("package.name").replaceAll("\\.", "/"));
                    if (!Objects.equals("", rb.getString("module.name"))) {
                        expandSb.append("/").append(rb.getString("module.name").replaceAll("\\.", "/"));
                    }
                    expandSb.append("/service");
                    String entityFile = String.format((expandSb + File.separator + "%s" + ".java"), tableInfo.getServiceName());
                    return entityFile;
                }
            });
        }

        //service.impl
        String serviceImplMark = rb.getString("service.impl.create.mark");
        if (null == serviceImplMark || Objects.equals("", serviceImplMark.trim()) || Boolean.valueOf(serviceImplMark)) {
            focList.add(new FileOutConfig(rb.getString("template.service.impl")) {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    StringBuffer expandSb = new StringBuffer(defaultDirR);
                    expandSb.append("/").append(rb.getString("package.name").replaceAll("\\.", "/"));
                    if (!Objects.equals("", rb.getString("module.name"))) {
                        expandSb.append("/").append(rb.getString("module.name").replaceAll("\\.", "/"));
                    }
                    expandSb.append("/service/impl");
                    String serviceName = bool ? tableInfo.getEntityName().split(entitySuffix)[0] : tableInfo.getEntityName();
                    StringBuffer sb = new StringBuffer(serviceName).append("Mapper");
                    map.put("mapperName",(new StringBuilder()).append(Character.toLowerCase(sb.charAt(0))).append(sb.substring(1)).toString());
                    String entityFile = String.format((expandSb + File.separator + "%s" + ".java"), tableInfo.getServiceImplName());
                    return entityFile;
                }
            });
        }

        //mapper
        String mapperMark = rb.getString("mapper.create.mark");
        if (null == mapperMark || Objects.equals("", mapperMark.trim()) || Boolean.valueOf(mapperMark)) {
            focList.add(new FileOutConfig(rb.getString("template.mapper")) {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    StringBuffer expandSb = new StringBuffer(daoDirR);
                    expandSb.append("/").append(rb.getString("package.name").replaceAll("\\.", "/"));
                    if (!Objects.equals("", rb.getString("module.name"))) {
                        expandSb.append("/").append(rb.getString("module.name").replaceAll("\\.", "/"));
                    }
                    expandSb.append("/mapper");
                    String entityFile = String.format((expandSb + File.separator + "%s" + ".java"), tableInfo.getMapperName());
                    return entityFile;
                }
            });
        }

        //mapper.xml
        String mapperXmlMark = rb.getString("mapper.xml.create.mark");
        if (null == mapperXmlMark || Objects.equals("", mapperXmlMark.trim()) || Boolean.valueOf(mapperXmlMark)) {
            focList.add(new FileOutConfig(rb.getString("template.mapper.xml")) {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    StringBuffer expandSb = new StringBuffer(daoDirR);
                    expandSb.append("/").append(rb.getString("package.name").replaceAll("\\.", "/"));
                    if (!Objects.equals("", rb.getString("module.name"))) {
                        expandSb.append("/").append(rb.getString("module.name").replaceAll("\\.", "/"));
                    }
                    expandSb.append("/mapper/xml");
                    String entityFile = String.format((expandSb + File.separator + "%s" + ".xml"), tableInfo.getXmlName());
                    return entityFile;
                }
            });
        }

        //entity
        String entityMark = rb.getString("entity.create.mark");
        if (null == entityMark || Objects.equals("", entityMark) || Boolean.valueOf(entityMark)) {
            focList.add(new FileOutConfig(rb.getString("template.entity")) {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    StringBuffer expandSb = new StringBuffer(daoDirR);
                    expandSb.append("/").append(rb.getString("package.name").replaceAll("\\.", "/"));
                    if (!Objects.equals("", rb.getString("module.name"))) {
                        expandSb.append("/").append(rb.getString("module.name").replaceAll("\\.", "/"));
                    }
                    expandSb.append("/entity");
                    String entityFile = String.format((expandSb + File.separator + "%s" + ".java"), tableInfo.getEntityName());
                    return entityFile;
                }
            });
        }

        // 自定义配置,初始化信息
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                map.put("dtoPackageName", pc.getParent() + ".dto");
                map.put("voPackageName", pc.getParent() + ".vo");
                String voClassName = rb.getString("super.vo.class.name"),
                       dtoClassName = rb.getString("super.dto.class.name"),
                        voClassPath = voClassName,
                        dtoClassPath = dtoClassName;
                if(null == dtoClassName || Objects.equals("", dtoClassName.trim())){
                    dtoClassPath = null;
                    dtoClassName = null;
                }else{
                    dtoClassName = dtoClassName.substring(dtoClassName.lastIndexOf(".") + 1, dtoClassName.length());
                }
                if(null == voClassName || Objects.equals("", voClassName.trim())){
                    voClassPath = null;
                    voClassName = null;
                }else{
                    voClassName = voClassName.substring(voClassName.lastIndexOf(".") + 1, voClassName.length());
                }
                map.put("dtoClassName", dtoClassName);
                map.put("dtoClassPath", dtoClassPath);
                map.put("voClassPath", voClassPath);
                map.put("voClassName", voClassName);
                this.setMap(map);
            }
        };

        TemplateConfig templateConfig = new TemplateConfig();
        templateConfig.setController(null);
        templateConfig.setService(null);
        templateConfig.setServiceImpl(null);
        templateConfig.setMapper(null);
        templateConfig.setXml(null);
        templateConfig.setEntity(null);
        mpg.setTemplate(templateConfig);

        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);
        mpg.execute();
    }
}
